package websocket

import (
	"fmt"
	"net/http"
	"strconv"
	"strings"
	"sync"
	"time"

	"data_service/models"
	"github.com/gorilla/websocket"
	"github.com/zeromicro/go-zero/core/logx"
)

// 服务WebSocket连接
func (s *WebSocketServer) ServeWS(w http.ResponseWriter, r *http.Request, userID, roomID, userName string) {
	maxUsers := 20
	if v := r.URL.Query().Get("max_users"); v != "" {
		if n, err := strconv.Atoi(v); err == nil && n > 0 {
			maxUsers = n
		}
	}

	// 从请求中获取游戏类型
	gameType := r.URL.Query().Get("gameType")

	conn, err := s.upgrader.Upgrade(w, r, nil)
	if err != nil {
		logx.Errorf("[ServeWS] WebSocket连接升级失败: %v", err)
		return
	}

	// 创建客户端
	client := &Client{
		UserID:     userID,
		UserName:   userName,
		Conn:       conn,
		Send:       make(chan []byte, 256),
		Mu:         sync.Mutex{},
		sendClosed: false,
	}

	// 处理游戏房间
	if gameType != "" {
		// 游戏房间逻辑
		var gameRoom *GameRoom

		// 如果提供了roomID，尝试加入指定游戏房间
		if roomID != "" {
			gameRoom = s.GetGameRoom(roomID)
			if gameRoom == nil {
				// 房间不存在，返回错误
				http.Error(w, "游戏房间不存在", http.StatusNotFound)
				conn.Close()
				return
			}

			// 检查房间是否已满
			gameRoom.mu.RLock()
			full := len(gameRoom.Clients) >= gameRoom.MaxUsers
			gameRoom.mu.RUnlock()
			if full {
				http.Error(w, "游戏房间已满", http.StatusBadRequest)
				conn.Close()
				return
			}
		} else {
			// 否则，获取或创建可加入的游戏房间
			gameRoom = s.GetOrCreateGameRoomForJoin(gameType)
		}

		// 添加客户端到游戏房间
		gameRoom.AddClient(client)

		// 启动客户端的读写协程
		go client.WritePump()
		go client.ReadPumpGame(gameRoom)

		// 发送欢迎消息到游戏房间
		joinMsg := Message{
			Type:     int(MessageTypeJoin),
			UserID:   userID,
			UserName: userName,
			Content:  fmt.Sprintf("%s 加入了游戏房间", userName),
			Time:     time.Now().Unix(),
		}
		gameRoom.Broadcast(joinMsg)

		logx.Infof("[ServeWS] 用户 %s(%s) 加入游戏房间 %s (类型: %s)", userName, userID, gameRoom.ID, gameType)
	} else {
		// 普通房间逻辑
		if roomID == "" {
			http.Error(w, "房间ID不能为空", http.StatusBadRequest)
			conn.Close()
			return
		}

		// 尝试获取房间
		room := s.GetRoom(roomID)

		// 如果房间不存在，尝试创建或恢复
		if room == nil {
			// 判断roomID是否为数字
			if _, err := strconv.Atoi(roomID); err == nil {
				// 是数字，查数据库
				var dbRoom models.Room
				err := s.DB.First(&dbRoom, roomID).Error
				if err == nil {
					// 数据库有，创建内存房间
					room = &Room{
						ID:          fmt.Sprintf("%d", dbRoom.ID),
						Name:        dbRoom.Name,
						CreatorID:   strconv.Itoa(dbRoom.CreatorID),
						CreatorName: dbRoom.CreatorName,
						Clients:     make(map[string]*Client),
						UserNames:   make(map[string]string),
						JoinTimes:   make(map[string]int64),
						Ready:       make(map[string]bool),
						MaxUsers:    maxUsers,
						wsServer:    s,
					}
					s.Mu.Lock()
					s.Rooms[room.ID] = room
					s.Mu.Unlock()
				} else {
					// 数据库没有，创建新房间并保存到数据库
					roomName := "chat"
					// 根据URL判断是否为游戏房间
					referer := r.Header.Get("Referer")
					if strings.Contains(referer, "snake") {
						roomName = "snake"
						maxUsers = 2
					} else if strings.Contains(referer, "gomoku") {
						roomName = "gomoku"
						maxUsers = 2
					} else if strings.Contains(referer, "tictactoe") {
						roomName = "tictactoe"
						maxUsers = 2
					}

					// 创建数据库记录
					creatorIDInt, _ := strconv.Atoi(userID)
					dbRoom = models.Room{
						Name:        roomName,
						CreatorID:   creatorIDInt,
						CreatorName: userName,
						Tag:         "game",
					}
					err := s.DB.Create(&dbRoom).Error
					if err == nil {
						// 创建内存房间，使用数据库生成的ID
						room = &Room{
							ID:          fmt.Sprintf("%d", dbRoom.ID),
							Name:        roomName,
							CreatorID:   userID,
							CreatorName: userName,
							Clients:     make(map[string]*Client),
							UserNames:   make(map[string]string),
							JoinTimes:   make(map[string]int64),
							Ready:       make(map[string]bool),
							MaxUsers:    maxUsers,
							wsServer:    s,
						}
						s.Mu.Lock()
						s.Rooms[room.ID] = room
						s.Mu.Unlock()
					} else {
						// 数据库创建失败，创建内存房间
						room = &Room{
							ID:          roomID,
							Name:        roomName,
							CreatorID:   userID,
							CreatorName: userName,
							Clients:     make(map[string]*Client),
							UserNames:   make(map[string]string),
							JoinTimes:   make(map[string]int64),
							Ready:       make(map[string]bool),
							MaxUsers:    maxUsers,
							wsServer:    s,
						}
						s.Mu.Lock()
						s.Rooms[roomID] = room
						s.Mu.Unlock()
					}
				}
			} else {
				// 不是数字，自动新建内存房间
				roomName := "snake"
				room = &Room{
					ID:          roomID,
					Name:        roomName,
					CreatorID:   userID,
					CreatorName: userName,
					Clients:     make(map[string]*Client),
					UserNames:   make(map[string]string),
					JoinTimes:   make(map[string]int64),
					Ready:       make(map[string]bool),
					MaxUsers:    maxUsers,
					wsServer:    s,
				}
				s.Mu.Lock()
				s.Rooms[roomID] = room
				s.Mu.Unlock()
			}
		}

		// 检查房间是否已满
		room.Mu.RLock()
		full := len(room.Clients) >= room.MaxUsers
		room.Mu.RUnlock()
		if full {
			_ = conn.WriteMessage(websocket.TextMessage, []byte(`{"type":99,"content":"房间已满"}`))
			conn.Close()
			return
		}

		// 添加客户端到房间
		room.AddClient(client)

		// 启动读写goroutine
		go client.WritePump()
		go client.ReadPump(room)

		// 创建加入消息
		joinMsg := Message{
			Type:     int(MessageTypeJoin),
			UserID:   userID,
			UserName: userName,
			Content:  fmt.Sprintf("%s 加入了房间", userName),
			Time:     time.Now().Unix(),
		}
		room.Broadcast(joinMsg)

		logx.Infof("[ServeWS] 用户 %s(%s) 加入房间 %s", userName, userID, roomID)
	}
}

// 获取房间内的用户列表
func (r *Room) GetUserList() []map[string]interface{} {
	r.Mu.RLock()
	defer r.Mu.RUnlock()

	var users []map[string]interface{}
	for userID, userName := range r.UserNames {
		users = append(users, map[string]interface{}{
			"user_id":   userID,
			"user_name": userName,
			"ready":     r.Ready[userID],
		})
	}
	return users
}

// 获取所有房间信息
func (s *WebSocketServer) GetAllRoomsInfo() []map[string]interface{} {
	s.Mu.RLock()
	defer s.Mu.RUnlock()

	var roomsInfo []map[string]interface{}
	for _, room := range s.Rooms {
		room.Mu.RLock()
		userCount := len(room.Clients)
		room.Mu.RUnlock()

		roomsInfo = append(roomsInfo, map[string]interface{}{
			"id":           room.ID,
			"name":         room.Name,
			"user_count":   userCount,
			"creator_id":   room.CreatorID,
			"creator_name": room.CreatorName,
			"max_users":    room.MaxUsers,
		})
	}
	return roomsInfo
}
